/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import Animated, { SharedValue, useDerivedValue } from 'react-native-reanimated';
import { normalizeSnapPoint } from '../utilities';
import {
  INITIAL_CONTAINER_HEIGHT,
  INITIAL_HANDLE_HEIGHT,
  INITIAL_SNAP_POINT,
  DEFAULT_SNAP_POINT,
  MAX_SNAP_POINT_PERCENTAGE,
  MIN_SNAP_POINT_PERCENTAGE,
} from '../components/adaptiveBottomSheet/constants';
import { AdaptiveBottomSheetProps } from '../components/adaptiveBottomSheet';

const extractSnapPointsValue = (snapPoints: AdaptiveBottomSheetProps['snapPoints']): string | number | Array<string | number> => {
  'worklet';
  const isSharedValue = snapPoints && typeof snapPoints === 'object' && snapPoints !== null && (snapPoints as SharedValue<unknown>).value !== undefined;
  return (isSharedValue ? (snapPoints as SharedValue<string | number | Array<string | number>>).value : snapPoints ?? DEFAULT_SNAP_POINT) as
    | string
    | number
    | Array<string | number>;
};

const isFullScreenMode = (snapPointValue: string | number, containerHeight: number): boolean => {
  'worklet';
  return (typeof snapPointValue === 'string' && snapPointValue.trim() === '100%') || (typeof snapPointValue === 'number' && snapPointValue >= containerHeight);
};

const calculateDynamicPosition = (containerHeight: number, contentHeight: number, handleHeight: number, maxDynamicContentSize: number | undefined): number => {
  'worklet';
  const maxSize = maxDynamicContentSize !== undefined ? maxDynamicContentSize : containerHeight;
  return containerHeight - Math.min(contentHeight + handleHeight, maxSize);
};

const processArraySnapPoints = (
  snapPoints: Array<string | number>,
  containerHeight: number,
  contentHeight: number,
  handleHeight: number,
  enableDynamicSizing: boolean | undefined,
  maxDynamicContentSize: number | undefined,
): number[] => {
  'worklet';
  let normalized = snapPoints.map(snapPoint => normalizeSnapPoint(snapPoint, containerHeight)) as number[];

  if (enableDynamicSizing === true) {
    if (handleHeight === INITIAL_HANDLE_HEIGHT || contentHeight === INITIAL_CONTAINER_HEIGHT) {
      return [INITIAL_SNAP_POINT];
    }

    const dynamicPosition = calculateDynamicPosition(containerHeight, contentHeight, handleHeight, maxDynamicContentSize);
    normalized.push(dynamicPosition);
    normalized = normalized.sort((a, b) => b - a);
  }

  return normalized;
};

const processSingleValueSnapPoints = (
  snapPointValue: string | number,
  containerHeight: number,
  contentHeight: number,
  handleHeight: number,
  enableDynamicSizing: boolean | undefined,
  maxDynamicContentSize: number | undefined,
): number[] => {
  'worklet';

  if (isFullScreenMode(snapPointValue, containerHeight)) {
    return [0, 0, 0, 1]; 
  }

  const maxPosition = containerHeight * (1 - MAX_SNAP_POINT_PERCENTAGE); // 90%
  const minPosition = containerHeight * (1 - MIN_SNAP_POINT_PERCENTAGE); // 40%

  if (enableDynamicSizing === true) {
    if (handleHeight === INITIAL_HANDLE_HEIGHT || contentHeight === INITIAL_CONTAINER_HEIGHT) {
      return [INITIAL_SNAP_POINT];
    }

    const dynamicPosition = calculateDynamicPosition(containerHeight, contentHeight, handleHeight, maxDynamicContentSize);
    const clampedDefault = Math.max(maxPosition, Math.min(minPosition, dynamicPosition));
    return [clampedDefault, minPosition, maxPosition, 0];
  }

  const defaultPosition = normalizeSnapPoint(snapPointValue, containerHeight);
  const clampedDefault = Math.max(maxPosition, Math.min(minPosition, defaultPosition));
  return [clampedDefault, minPosition, maxPosition, 0];
};

export const useNormalizedSnapPoints = (
  snapPoints: AdaptiveBottomSheetProps['snapPoints'],
  containerHeight: SharedValue<number>,
  contentHeight: SharedValue<number>,
  handleHeight: SharedValue<number>,
  enableDynamicSizing: AdaptiveBottomSheetProps['enableDynamicSizing'],
  maxDynamicContentSize: AdaptiveBottomSheetProps['maxDynamicContentSize'],
): Animated.SharedValue<number[]> => {
  const normalizedSnapPoints = useDerivedValue(() => {
    if (containerHeight.value === INITIAL_CONTAINER_HEIGHT) {
      return [INITIAL_SNAP_POINT];
    }

    const snapPointsValue = extractSnapPointsValue(snapPoints);

    if (Array.isArray(snapPointsValue)) {
      return processArraySnapPoints(
        snapPointsValue,
        containerHeight.value,
        contentHeight.value,
        handleHeight.value,
        enableDynamicSizing,
        maxDynamicContentSize,
      );
    } else {
      return processSingleValueSnapPoints(
        snapPointsValue,
        containerHeight.value,
        contentHeight.value,
        handleHeight.value,
        enableDynamicSizing,
        maxDynamicContentSize,
      );
    }
  }, [snapPoints, enableDynamicSizing, maxDynamicContentSize]);

  return normalizedSnapPoints;
};
